/*     */ package com.zimbra.cs.mailbox;
/*     */ 
/*     */ import com.zimbra.common.service.ServiceException;
/*     */ import com.zimbra.common.stats.Counter;
/*     */ import com.zimbra.common.util.ByteUtil;
/*     */ import com.zimbra.common.util.Log;
/*     */ import com.zimbra.common.util.LogFactory;
/*     */ import com.zimbra.common.util.ZimbraLog;
/*     */ import com.zimbra.cs.account.Provisioning;
/*     */ import com.zimbra.cs.account.Server;
/*     */ import com.zimbra.cs.db.DbMailItem;
/*     */ import com.zimbra.cs.mime.ExpandMimeMessage;
/*     */ import com.zimbra.cs.mime.Mime.FixedMimeMessage;
/*     */ import com.zimbra.cs.stats.ZimbraPerf;
/*     */ import com.zimbra.cs.store.MailboxBlob;
/*     */ import com.zimbra.cs.store.StoreManager;
/*     */ import com.zimbra.cs.util.JMSession;
/*     */ import java.io.IOException;
/*     */ import java.io.InputStream;
/*     */ import java.util.Iterator;
/*     */ import java.util.LinkedHashMap;
/*     */ import java.util.Map;
/*     */ import java.util.Map.Entry;
/*     */ import java.util.Set;
/*     */ import javax.mail.MessagingException;
/*     */ import javax.mail.internet.MimeMessage;
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ public class MessageCache
/*     */ {
/*  44 */   private static final Log sLog = LogFactory.getLog(MessageCache.class);
/*     */   
/*     */   private static final class CacheNode
/*     */   {
/*     */     MimeMessage message;
/*     */     MimeMessage expanded;
/*  50 */     long size = 0L;
/*     */   }
/*     */   
/*     */ 
/*  54 */   private static Map<String, CacheNode> sCache = new LinkedHashMap(150, 0.75F, true);
/*     */   
/*     */ 
/*     */   private static int sMaxCacheSize;
/*     */   
/*  59 */   private static volatile long sDataSize = 0L;
/*     */   private static final int MESSAGE_CACHE_DISK_STREAMING_THRESHOLD = 4096;
/*     */   
/*     */   static {
/*  63 */     try { loadSettings();
/*     */     } catch (ServiceException e) {
/*  65 */       throw new RuntimeException(e);
/*     */     }
/*     */   }
/*     */   
/*     */   public static void loadSettings() throws ServiceException {
/*  70 */     sMaxCacheSize = Provisioning.getInstance().getLocalServer().getMessageCacheSize();
/*  71 */     ZimbraLog.cache.info("setting message cache size to " + sMaxCacheSize);
/*     */   }
/*     */   
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */   public static long getDataSize()
/*     */   {
/*  88 */     return sDataSize;
/*     */   }
/*     */   
/*     */ 
/*     */ 
/*     */   static void purge(MailItem item)
/*     */   {
/*  95 */     String digest = item.getDigest();
/*  96 */     if (digest != null) {
/*  97 */       sLog.debug("Purging item %d from the message cache.", new Object[] { Integer.valueOf(item.getId()) });
/*  98 */       purge(item.getDigest());
/*     */     }
/*     */   }
/*     */   
/*     */ 
/*     */ 
/*     */   static void purge(Mailbox mbox, int itemId)
/*     */   {
/* 106 */     String digest = null;
/*     */     try {
/* 108 */       digest = DbMailItem.getBlobDigest(mbox, itemId);
/*     */     } catch (ServiceException e) {
/* 110 */       sLog.warn("Unable to uncache message for item %d.", Integer.valueOf(itemId), e);
/*     */     }
/* 112 */     if (digest != null) {
/* 113 */       sLog.debug("Purging item %d from the message cache.", new Object[] { Integer.valueOf(itemId) });
/* 114 */       purge(digest);
/*     */     }
/*     */   }
/*     */   
/*     */ 
/*     */ 
/*     */   public static void purge(String digest)
/*     */   {
/* 122 */     if (digest != null) {
/* 123 */       synchronized (sCache) {
/* 124 */         CacheNode node = (CacheNode)sCache.remove(digest);
/* 125 */         if (node != null) {
/* 126 */           sLog.debug("Purged digest %s from the message cache.", new Object[] { digest });
/* 127 */           sDataSize -= node.size;
/*     */         }
/*     */       }
/*     */     }
/*     */   }
/*     */   
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */   static MimeMessage getMimeMessage(MailItem item, boolean expand)
/*     */     throws ServiceException
/*     */   {
/* 148 */     String digest = item.getDigest();
/* 149 */     CacheNode cnode = null;
/* 150 */     boolean cacheHit = true;
/* 151 */     boolean newNode = false;
/* 152 */     InputStream in = null;
/*     */     
/* 154 */     synchronized (sCache) {
/* 155 */       cnode = (CacheNode)sCache.get(digest);
/* 156 */       if (cnode == null) {
/* 157 */         newNode = true;
/* 158 */         cnode = new CacheNode();
/*     */       }
/*     */     }
/*     */     try
/*     */     {
/* 163 */       if (cnode.message == null) {
/* 164 */         sLog.debug("Loading MimeMessage for item %d.", new Object[] { Integer.valueOf(item.getId()) });
/* 165 */         cacheHit = false;
/*     */         try {
/* 167 */           in = fetchFromStore(item);
/* 168 */           cnode.message = new Mime.FixedMimeMessage(JMSession.getSession(), in);
/* 169 */           if (item.getSize() < 4096L) {
/* 170 */             cnode.size = item.getSize();
/*     */             
/*     */ 
/*     */ 
/* 174 */             sDataSize += cnode.size;
/*     */           }
/*     */         }
/*     */         finally {}
/*     */       }
/*     */       
/*     */ 
/* 181 */       if ((expand) && (cnode.expanded == null)) {
/* 182 */         sLog.debug("Expanding MimeMessage for item %d.", new Object[] { Integer.valueOf(item.getId()) });
/* 183 */         cacheHit = false;
/*     */         try {
/* 185 */           ExpandMimeMessage expander = new ExpandMimeMessage(cnode.message);
/* 186 */           expander.expand();
/* 187 */           cnode.expanded = expander.getExpanded();
/* 188 */           if (cnode.expanded != cnode.message) {
/* 189 */             sDataSize += cnode.size;
/* 190 */             cnode.size *= 2L;
/*     */           }
/*     */         }
/*     */         catch (Exception e) {
/* 194 */           sLog.warn("MIME converter failed for message %d.  Reverting to original.", Integer.valueOf(item.getId()), e);
/* 195 */           cnode.expanded = cnode.message;
/*     */         }
/*     */       }
/*     */       
/* 199 */       if (newNode) {
/* 200 */         cacheItem(digest, cnode);
/*     */       }
/*     */     } catch (IOException e) {
/* 203 */       throw ServiceException.FAILURE("IOException while retrieving content for item " + item.getId(), e);
/*     */     } catch (MessagingException e) {
/* 205 */       throw ServiceException.FAILURE("MessagingException while creating MimeMessage for item " + item.getId(), e);
/*     */     } finally {
/* 207 */       ByteUtil.closeStream(in);
/*     */     }
/*     */     
/* 210 */     if (cacheHit) {
/* 211 */       sLog.debug("Cache hit for item %d: digest=%s, expand=%b.", new Object[] { Integer.valueOf(item.getId()), item.getDigest(), Boolean.valueOf(expand) });
/* 212 */       ZimbraPerf.COUNTER_MBOX_MSG_CACHE.increment(100L);
/*     */     } else {
/* 214 */       sLog.debug("Cache miss for item %d: digest=%s, expand=%b.", new Object[] { Integer.valueOf(item.getId()), item.getDigest(), Boolean.valueOf(expand) });
/* 215 */       ZimbraPerf.COUNTER_MBOX_MSG_CACHE.increment(0L);
/*     */     }
/*     */     
/* 218 */     if (expand) {
/* 219 */       return cnode.expanded;
/*     */     }
/* 221 */     return cnode.message;
/*     */   }
/*     */   
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */   static InputStream fetchFromStore(MailItem item)
/*     */     throws ServiceException, IOException
/*     */   {
/* 231 */     MailboxBlob mblob = item.getBlob();
/* 232 */     if (mblob == null) {
/* 233 */       throw ServiceException.FAILURE("missing blob for id: " + item.getId() + ", change: " + item.getModifiedSequence(), null);
/*     */     }
/* 235 */     if (item.getSize() < 4096L) {
/* 236 */       return StoreManager.getInstance().getContent(mblob);
/*     */     }
/* 238 */     return StoreManager.getInstance().getContent(mblob.getLocalBlob());
/*     */   }
/*     */   
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */   public static void cacheMessage(String digest, MimeMessage original, MimeMessage expanded)
/*     */   {
/* 249 */     sLog.debug("Caching existing MimeMessage, digest=%s.", new Object[] { digest });
/* 250 */     CacheNode cnode = new CacheNode();
/* 251 */     cnode.message = original;
/* 252 */     cnode.expanded = expanded;
/* 253 */     cacheItem(digest, cnode);
/*     */   }
/*     */   
/*     */   private static void cacheItem(String digest, CacheNode cnode) {
/* 257 */     sLog.debug("Caching MimeMessage for digest %s.", new Object[] { digest });
/* 258 */     synchronized (sCache) {
/* 259 */       sCache.put(digest, cnode);
/*     */       
/*     */ 
/*     */ 
/* 263 */       if (sCache.size() > sMaxCacheSize) {
/* 264 */         Iterator<Map.Entry<String, CacheNode>> it = sCache.entrySet().iterator();
/* 265 */         while ((sCache.size() > sMaxCacheSize) && (it.hasNext())) {
/* 266 */           Map.Entry<String, CacheNode> entry = (Map.Entry)it.next();
/* 267 */           sLog.debug("Pruning digest %s from the cache.", new Object[] { entry.getKey() });
/* 268 */           it.remove();
/* 269 */           sDataSize -= ((CacheNode)entry.getValue()).size;
/*     */         }
/*     */       }
/*     */     }
/*     */   }
/*     */   
/*     */   /* Error */
/*     */   public static int getSize()
/*     */   {
/*     */     // Byte code:
/*     */     //   0: getstatic 14	com/zimbra/cs/mailbox/MessageCache:sCache	Ljava/util/Map;
/*     */     //   3: dup
/*     */     //   4: astore_0
/*     */     //   5: monitorenter
/*     */     //   6: getstatic 14	com/zimbra/cs/mailbox/MessageCache:sCache	Ljava/util/Map;
/*     */     //   9: invokeinterface 15 1 0
/*     */     //   14: aload_0
/*     */     //   15: monitorexit
/*     */     //   16: ireturn
/*     */     //   17: astore_1
/*     */     //   18: aload_0
/*     */     //   19: monitorexit
/*     */     //   20: aload_1
/*     */     //   21: athrow
/*     */     // Line number table:
/*     */     //   Java source line #76	-> byte code offset #0
/*     */     //   Java source line #77	-> byte code offset #6
/*     */     //   Java source line #78	-> byte code offset #17
/*     */     // Local variable table:
/*     */     //   start	length	slot	name	signature
/*     */     //   4	15	0	Ljava/lang/Object;	Object
/*     */     //   17	4	1	localObject1	Object
/*     */     // Exception table:
/*     */     //   from	to	target	type
/*     */     //   6	16	17	finally
/*     */     //   17	20	17	finally
/*     */   }
/*     */   
/*     */   /* Error */
/*     */   public static boolean contains(String digest)
/*     */   {
/*     */     // Byte code:
/*     */     //   0: getstatic 14	com/zimbra/cs/mailbox/MessageCache:sCache	Ljava/util/Map;
/*     */     //   3: dup
/*     */     //   4: astore_1
/*     */     //   5: monitorenter
/*     */     //   6: getstatic 14	com/zimbra/cs/mailbox/MessageCache:sCache	Ljava/util/Map;
/*     */     //   9: aload_0
/*     */     //   10: invokeinterface 16 2 0
/*     */     //   15: aload_1
/*     */     //   16: monitorexit
/*     */     //   17: ireturn
/*     */     //   18: astore_2
/*     */     //   19: aload_1
/*     */     //   20: monitorexit
/*     */     //   21: aload_2
/*     */     //   22: athrow
/*     */     // Line number table:
/*     */     //   Java source line #82	-> byte code offset #0
/*     */     //   Java source line #83	-> byte code offset #6
/*     */     //   Java source line #84	-> byte code offset #18
/*     */     // Local variable table:
/*     */     //   start	length	slot	name	signature
/*     */     //   0	23	0	digest	String
/*     */     //   4	16	1	Ljava/lang/Object;	Object
/*     */     //   18	4	2	localObject1	Object
/*     */     // Exception table:
/*     */     //   from	to	target	type
/*     */     //   6	17	18	finally
/*     */     //   18	21	18	finally
/*     */   }
/*     */ }


/* Location:              /home/mint/zimbrastore.jar!/com/zimbra/cs/mailbox/MessageCache.class
 * Java compiler version: 7 (51.0)
 * JD-Core Version:       0.7.1
 */